{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "d:\\anaconda\\envs\\pytorch\\lib\\site-packages\\tqdm\\auto.py:22: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
      "  from .autonotebook import tqdm as notebook_tqdm\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "==================== 0 ====================\n",
      "Input size: torch.Size([1, 4])\n",
      "outputs size: torch.Size([1, 2])\n",
      "tensor([[ 0.1733, -0.0338]], grad_fn=<TanhBackward0>)\n",
      "==================== 1 ====================\n",
      "Input size: torch.Size([1, 4])\n",
      "outputs size: torch.Size([1, 2])\n",
      "tensor([[-0.4462, -0.7485]], grad_fn=<TanhBackward0>)\n",
      "==================== 2 ====================\n",
      "Input size: torch.Size([1, 4])\n",
      "outputs size: torch.Size([1, 2])\n",
      "tensor([[0.9088, 0.9229]], grad_fn=<TanhBackward0>)\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "\n",
    "batch_size=1\n",
    "seq_len=3\n",
    "input_size=4\n",
    "hidden_size=2\n",
    " \n",
    "cell=torch.nn.RNNCell(input_size=input_size,hidden_size=hidden_size)\n",
    " \n",
    "dataset=torch.randn(seq_len,batch_size,input_size)\n",
    "hidden=torch.zeros(batch_size,hidden_size)\n",
    " \n",
    "for idx,input in enumerate(dataset):\n",
    "    print('='*20,idx,'='*20)\n",
    "    print('Input size:',input.shape)\n",
    " \n",
    "    hidden=cell(input,hidden)\n",
    " \n",
    "    print('outputs size:',hidden.shape)\n",
    "    print(hidden)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Predicted string: ehoho,Epoch[1/15] loss=7.3218\n",
      "Predicted string: ooooo,Epoch[2/15] loss=6.0225\n",
      "Predicted string: ooooo,Epoch[3/15] loss=5.5175\n",
      "Predicted string: ooool,Epoch[4/15] loss=5.1850\n",
      "Predicted string: ooool,Epoch[5/15] loss=4.8282\n",
      "Predicted string: ohool,Epoch[6/15] loss=4.4031\n",
      "Predicted string: ohlol,Epoch[7/15] loss=4.0159\n",
      "Predicted string: ohlol,Epoch[8/15] loss=3.7461\n",
      "Predicted string: ohlol,Epoch[9/15] loss=3.5429\n",
      "Predicted string: ohlol,Epoch[10/15] loss=3.3617\n",
      "Predicted string: ohlol,Epoch[11/15] loss=3.2083\n",
      "Predicted string: lhlol,Epoch[12/15] loss=3.0810\n",
      "Predicted string: lhlol,Epoch[13/15] loss=2.9642\n",
      "Predicted string: lhlol,Epoch[14/15] loss=2.8446\n",
      "Predicted string: ohlol,Epoch[15/15] loss=2.7194\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    " \n",
    "input_size=4\n",
    "hidden_size=4\n",
    "batch_size=1\n",
    " \n",
    "idx2char=['e','h','l','o']\n",
    "x_data=[1,0,2,2,3]\n",
    "y_data=[3,1,2,3,2]\n",
    " \n",
    "one_hot_lookup=[[1,0,0,0],\n",
    "                [0,1,0,0],\n",
    "                [0,0,1,0],\n",
    "                [0,0,0,1]]\n",
    "x_one_hot=[one_hot_lookup[x] for x in x_data]\n",
    " \n",
    "inputs=torch.Tensor(x_one_hot).view(-1,batch_size,input_size)#seq_len,batch_size,input_size5,1,4\n",
    "labels=torch.LongTensor(y_data).view(-1,1)#将 y_data 转换为 PyTorch 的 LongTensor，并将其形状改为只有一列\n",
    " \n",
    "class Model(torch.nn.Module):\n",
    "    def __init__(self,input_size,hidden_size,batch_size):\n",
    "        super(Model,self).__init__()\n",
    "        self.batch_size=batch_size\n",
    "        self.input_size=input_size\n",
    "        self.hidden_size=hidden_size\n",
    "        self.rnncell=torch.nn.RNNCell(input_size=self.input_size,hidden_size=self.hidden_size)\n",
    " \n",
    "    def forward(self,input,hidden):\n",
    "        hidden=self.rnncell(input,hidden)\n",
    "        return hidden\n",
    " \n",
    "    def init_hidden(self):\n",
    "        return torch.zeros(self.batch_size,self.hidden_size)\n",
    " \n",
    "net=Model(input_size,hidden_size,batch_size)\n",
    " \n",
    "#定义损失函数\n",
    "criterion=torch.nn.CrossEntropyLoss()\n",
    "#定义优化器\n",
    "optimizer=torch.optim.Adam(net.parameters(),lr=0.1)#Adam优化器\n",
    " \n",
    "for epoch in range(15):\n",
    "    loss=0\n",
    "    optimizer.zero_grad()#梯度清零\n",
    "    hidden=net.init_hidden()#隐藏状态初始化\n",
    "    print('Predicted string:',end=' ')\n",
    "    for input,label in zip(inputs,labels):\n",
    "        hidden=net(input,hidden)\n",
    "        # print()\n",
    "        loss+=criterion(hidden,label)# 使用损失函数 (criterion) 计算预测值 (hidden) 与实际标签 (label) 之间的损失，并将其加到总损失 (loss) 上。\n",
    "        _,idx=hidden.max(dim=1)\n",
    "        print(idx2char[idx.item()],end='')\n",
    "    loss.backward()\n",
    "    optimizer.step()\n",
    "    print(',Epoch[%d/15] loss=%.4f'%(epoch+1,loss.item()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Predicted: hhhhh,Epoch[1/15] loss=1.4255\n",
      "Predicted: hoooo,Epoch[2/15] loss=1.2000\n",
      "Predicted: ohool,Epoch[3/15] loss=1.0087\n",
      "Predicted: ohlol,Epoch[4/15] loss=0.8520\n",
      "Predicted: lhlol,Epoch[5/15] loss=0.7377\n",
      "Predicted: lhlol,Epoch[6/15] loss=0.6572\n",
      "Predicted: lhlol,Epoch[7/15] loss=0.5992\n",
      "Predicted: ohlol,Epoch[8/15] loss=0.5538\n",
      "Predicted: ohlol,Epoch[9/15] loss=0.5186\n",
      "Predicted: ohlol,Epoch[10/15] loss=0.4948\n",
      "Predicted: ohlol,Epoch[11/15] loss=0.4779\n",
      "Predicted: ohlol,Epoch[12/15] loss=0.4627\n",
      "Predicted: ohlol,Epoch[13/15] loss=0.4476\n",
      "Predicted: ohlol,Epoch[14/15] loss=0.4333\n",
      "Predicted: ohlol,Epoch[15/15] loss=0.4204\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    " \n",
    "input_size=4\n",
    "hidden_size=4\n",
    "num_layers=1\n",
    "batch_size=1\n",
    "seq_len=5\n",
    " \n",
    "idx2char=['e','h','l','o']\n",
    "x_data=[1,0,2,2,3]#hello\n",
    "y_data=[3,1,2,3,2]#ohlol\n",
    " \n",
    "one_hot_lookup=[[1,0,0,0],\n",
    "                [0,1,0,0],\n",
    "                [0,0,1,0],\n",
    "                [0,0,0,1]]\n",
    "x_one_hot=[one_hot_lookup[x] for x in x_data]\n",
    " \n",
    "inputs=torch.Tensor(x_one_hot).view(seq_len,batch_size,input_size)#seq_len,batch_size,input_size5,1,4\n",
    "labels=torch.LongTensor(y_data)#将 y_data 转换为 PyTorch 的 LongTensor\n",
    "class Model(torch.nn.Module):\n",
    "    def __init__(self,input_size,hidden_size,batch_size,num_layers=1):\n",
    "        super(Model,self).__init__()\n",
    "        self.num_layers=num_layers\n",
    "        self.batch_size=batch_size\n",
    "        self.input_size=input_size\n",
    "        self.hidden_size=hidden_size\n",
    "        self.rnn=torch.nn.RNN(input_size=self.input_size,hidden_size=self.hidden_size,num_layers=num_layers)\n",
    " \n",
    "    def forward(self,input):\n",
    "        hidden=torch.zeros(self.num_layers,self.batch_size,self.hidden_size)\n",
    "        # print('input：',input.shape)\n",
    "        # print('hidden:',hidden.shape)\n",
    "        out,_=self.rnn(input,hidden)\n",
    "        # print('out',out.shape)\n",
    "        # print(h.shape)\n",
    "        return out.view(-1,self.hidden_size)\n",
    "    #最后，返回的out张量被重塑（或展平）为一个二维张量，其中第一个维度是-1，意味着它会自动计算以保持元素总数不变。第二个维度是隐藏层的大小（self.hidden_size）。\n",
    " \n",
    "net=Model(input_size,hidden_size,batch_size,num_layers)\n",
    " \n",
    "#定义损失函数\n",
    "criterion=torch.nn.CrossEntropyLoss()#PyTorch 的 CrossEntropyLoss 内部会执行 softmax 操作，将预测分数转换为概率分布，然后计算交叉熵损失\n",
    "#定义优化器\n",
    "optimizer=torch.optim.Adam(net.parameters(),lr=0.1)#Adam优化器\n",
    "for epoch in range(15):\n",
    "    optimizer.zero_grad()#梯度清零\n",
    "    outputs=net(inputs)\n",
    "    # print(outputs.shape)\n",
    "    loss=criterion(outputs,labels)\n",
    "    loss.backward()\n",
    "    optimizer.step()\n",
    " \n",
    "    _,idx=outputs.max(dim=1)\n",
    "    idx=idx.data.numpy()#将张量转换为numpy array\n",
    "    print('Predicted:',''.join([idx2char[x] for x in idx]),end='')#将预测的索引转换为字符，并打印出来\n",
    "    print(',Epoch[%d/15] loss=%.4f'%(epoch+1,loss.item()))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "pytorch",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
